#include "Stopwatch.hpp"
#include "Clock.hpp"
#include "AssetManager.hpp"
#include "Notification.hpp"
#include "Util.hpp"
#include <cpp3ds/System/I18n.hpp>
#include <cpp3ds/System/FileSystem.hpp>
#include <TweenEngine/Tween.h>
#include <time.h>
#include <stdlib.h>

namespace Clock {

Stopwatch::Stopwatch()
: m_stopButtonInteract(false)
{
	m_textStopwatch.setString(":00");
	m_textStopwatch.useSystemFont();
	m_textStopwatch.setPosition(80.f, 60.f);
	m_textStopwatch.setFillColor(cpp3ds::Color(66, 66, 66));
	m_textStopwatch.setCharacterSize(24);
	m_textStopwatch.setOrigin(m_textStopwatch.getLocalBounds().width / 2, m_textStopwatch.getLocalBounds().height / 2);

	m_startButton.setRadius(20.f);
	m_startButton.setPosition(30.f, 210.f);
	m_startButton.setFillColor(cpp3ds::Color(0, 150, 136));
	m_startButton.setOutlineThickness(1);
	m_startButton.setOutlineColor(cpp3ds::Color(0, 105, 92));
	m_startButton.setOrigin(m_startButton.getLocalBounds().width / 2, m_startButton.getLocalBounds().height / 2);

	m_textStart.setPosition(m_startButton.getPosition().x, m_startButton.getPosition().y);
	m_textStart.setString("\uf04b");
	m_textStart.setFillColor(cpp3ds::Color::White);
	m_textStart.setOrigin(m_textStart.getLocalBounds().width / 2, m_textStart.getLocalBounds().height / 2);
	m_textStart.setCharacterSize(16);
	m_textStart.setOutlineThickness(1);
	m_textStart.setOutlineColor(cpp3ds::Color::Black);
	m_textStart.setFont(AssetManager<cpp3ds::Font>::get("fonts/fontawesome.ttf"));

	m_textStopwatchMilliseconds.setString("000");
	m_textStopwatchMilliseconds.useSystemFont();
	m_textStopwatchMilliseconds.setFillColor(g_themeColor);
	m_textStopwatchMilliseconds.setPosition(m_textStopwatch.getPosition().x, m_textStopwatch.getPosition().y + m_textStopwatch.getLocalBounds().height);
	m_textStopwatchMilliseconds.setCharacterSize(12);
	m_textStopwatchMilliseconds.setOrigin(m_textStopwatchMilliseconds.getLocalBounds().width / 2, m_textStopwatchMilliseconds.getLocalBounds().height / 2);

	m_stopButton = m_startButton;
	m_stopButton.setPosition(130.f, 210.f);
	m_stopButton.setFillColor(cpp3ds::Color(244, 67, 54, 0));
	m_stopButton.setOutlineColor(cpp3ds::Color(198, 40, 40, 0));

	m_textStop = m_textStart;
	m_textStop.setString("\uf04d");
	m_textStop.setOrigin(m_textStop.getLocalBounds().width / 2, m_textStop.getLocalBounds().height / 1.6f);
	m_textStop.setPosition(m_stopButton.getPosition().x, m_stopButton.getPosition().y);
	m_textStop.setFillColor(cpp3ds::Color(255, 255, 255, 0));
	m_textStop.setOutlineColor(cpp3ds::Color(0, 0, 0, 0));

	m_textAddLap = m_textStart;
	m_textAddLap.setString("\uf067");
	m_textAddLap.setOrigin(m_textAddLap.getLocalBounds().width, 0.f);
	m_textAddLap.setPosition(155.f, 36.f);

	m_textClearList = m_textStart;
	m_textClearList.setString("\uf00d");
	m_textClearList.setOrigin(m_textAddLap.getLocalBounds().width, 0.f);
	m_textClearList.setPosition(155.f, 130.f);

	m_scrollbarLapList.setPosition(313.f, 35.f);
	m_scrollbarLapList.setDragRect(cpp3ds::IntRect(160, 0, 160, 240));
	m_scrollbarLapList.setScrollAreaSize(cpp3ds::Vector2u(320, 230));
	m_scrollbarLapList.setSize(cpp3ds::Vector2u(8, 205));
	m_scrollbarLapList.setColor(cpp3ds::Color(150, 150, 150, 150));

	m_scrollbarLapList.attachObject(&m_lapList);
}

Stopwatch::~Stopwatch()
{

}

void Stopwatch::draw(cpp3ds::RenderTarget &target, cpp3ds::RenderStates states) const
{
	states.transform *= getTransform();

	target.draw(m_textStopwatch, states);
	target.draw(m_textStopwatchMilliseconds, states);

	target.draw(m_startButton, states);
	target.draw(m_textStart, states);

	if (m_stopButtonInteract) {
		target.draw(m_stopButton, states);
		target.draw(m_textStop, states);
	}

	target.draw(m_textAddLap, states);

	if (m_lapList.count() > 0)
		target.draw(m_textClearList, states);

	target.draw(m_lapList, states);
	target.draw(m_scrollbarLapList, states);
}

void Stopwatch::update(float delta)
{
	m_tweenManager.update(delta);
	m_scrollbarLapList.update(delta);
	m_lapList.update(delta);

	if (isRunning()) {
		m_textStopwatchMilliseconds.setString(_("%03d", m_mainStopwatch.getElapsedTime().asMilliseconds() % 1000));

		int seconds = (int)m_mainStopwatch.getElapsedTime().asSeconds() % 60;
		int minutes = (int)m_mainStopwatch.getElapsedTime().asSeconds() / 60;
		int hours = minutes / 60;

		cpp3ds::String newString;
		std::size_t actualSize = m_textStopwatch.getString().getSize();
		if (hours > 0) {
			newString = _("%i:%02d:%02d", hours, minutes % 60, seconds);
		} else if (minutes > 0) {
			newString = _("%i:%02d", minutes, seconds);
		} else {
			newString = _(":%02d", seconds);
		}

		m_textStopwatch.setString(newString);
		if (newString.getSize() != actualSize) {
			TweenEngine::Tween::to(m_textStopwatch, m_textStopwatch.ORIGIN_XY, 0.4f)
				.target(m_textStopwatch.getLocalBounds().width / 2, m_textStopwatch.getLocalBounds().height / 2)
				.start(m_tweenManager);
		}
	}
}

void Stopwatch::processEvent(const cpp3ds::Event& event)
{
	m_scrollbarLapList.processEvent(event);

	if (event.type == cpp3ds::Event::TouchEnded) {
		if (m_startButton.getGlobalBounds().contains(event.touch.x, event.touch.y)) {
			toggle();
		} else if (m_stopButton.getGlobalBounds().contains(event.touch.x, event.touch.y) && m_stopButtonInteract) {
			stop();
		} else if (m_textAddLap.getGlobalBounds().contains(event.touch.x, event.touch.y)) {
			m_lapList.addLap(m_mainStopwatch.getElapsedTime());
		} else if (m_textClearList.getGlobalBounds().contains(event.touch.x, event.touch.y) && m_lapList.count() > 0) {
			m_lapList.clearList();
		}
	} else if (event.type == cpp3ds::Event::KeyPressed) {
		switch (event.key.code) {
			case cpp3ds::Keyboard::A:
				toggle();
				break;
			case cpp3ds::Keyboard::X:
				m_lapList.addLap(m_mainStopwatch.getElapsedTime());
				break;
			case cpp3ds::Keyboard::Y:
				m_lapList.clearList();
				break;
		}
	}
}

void Stopwatch::play()
{
	m_mainStopwatch.resume();

	m_textStart.setString("\uf04c");
	m_textStart.setOrigin(m_textStart.getLocalBounds().width / 2, m_textStart.getLocalBounds().height / 1.6f);
	TweenEngine::Tween::to(m_startButton, m_startButton.FILL_COLOR_RGB, 0.4f)
		.target(255, 235, 59)
		.start(m_tweenManager);

	TweenEngine::Tween::to(m_startButton, m_startButton.OUTLINE_COLOR_RGB, 0.4f)
		.target(249, 168, 37)
		.start(m_tweenManager);

	m_stopButtonInteract = true;
	TweenEngine::Tween::to(m_stopButton, m_stopButton.FILL_COLOR_ALPHA, 0.4f)
		.target(255)
		.start(m_tweenManager);
	TweenEngine::Tween::to(m_stopButton, m_stopButton.OUTLINE_COLOR_ALPHA, 0.4f)
		.target(255)
		.start(m_tweenManager);

	TweenEngine::Tween::to(m_textStop, m_textStop.FILL_COLOR_ALPHA, 0.4f)
		.target(255)
		.start(m_tweenManager);
	TweenEngine::Tween::to(m_textStop, m_textStop.OUTLINE_COLOR_ALPHA, 0.4f)
		.target(255)
		.start(m_tweenManager);
}

void Stopwatch::pause()
{
	m_mainStopwatch.pause();

	m_textStart.setString("\uf04b");
	m_textStart.setOrigin(m_textStart.getLocalBounds().width / 2, m_textStart.getLocalBounds().height / 1.6f);
	TweenEngine::Tween::to(m_startButton, m_startButton.FILL_COLOR_RGB, 0.4f)
		.target(0, 150, 136)
		.start(m_tweenManager);

	TweenEngine::Tween::to(m_startButton, m_startButton.OUTLINE_COLOR_RGB, 0.4f)
		.target(0, 105, 92)
		.start(m_tweenManager);
}

void Stopwatch::stop()
{
	pause();
	reset();

	TweenEngine::Tween::to(m_stopButton, m_stopButton.FILL_COLOR_ALPHA, 0.4f)
		.target(0)
		.setCallback(TweenEngine::TweenCallback::COMPLETE, [=](TweenEngine::BaseTween* source) {
			m_stopButtonInteract = false;
		})
		.start(m_tweenManager);
	TweenEngine::Tween::to(m_stopButton, m_stopButton.OUTLINE_COLOR_ALPHA, 0.4f)
		.target(0)
		.start(m_tweenManager);

	TweenEngine::Tween::to(m_textStop, m_textStop.FILL_COLOR_ALPHA, 0.4f)
		.target(0)
		.start(m_tweenManager);
	TweenEngine::Tween::to(m_textStop, m_textStop.OUTLINE_COLOR_ALPHA, 0.4f)
		.target(0)
		.start(m_tweenManager);
}

void Stopwatch::toggle()
{
	if (!isRunning())
		play();
	else
		pause();
}

bool Stopwatch::isRunning()
{
	return m_mainStopwatch.isRunning();
}

cpp3ds::Time Stopwatch::getElapsedTime()
{
	return m_mainStopwatch.getElapsedTime();
}

void Stopwatch::reset()
{
	m_mainStopwatch.reset();

	m_textStopwatchMilliseconds.setString("000");

	m_textStopwatch.setString(":00");
	TweenEngine::Tween::to(m_textStopwatch, m_textStopwatch.ORIGIN_XY, 0.4f)
		.target(m_textStopwatch.getLocalBounds().width / 2, m_textStopwatch.getLocalBounds().height / 2)
		.start(m_tweenManager);
}

} // namespace Clock
